package compilarclassejava;

import java.lang.reflect.Method;
import java.util.LinkedList;

import entidadesparaguardardadosteste.CasoDeTeste;
import gui.AssociaClassesEMetodosANomes;
import gui.DeclaracaoDeMetodo;
import gui.FachadaManipulacaoClassesDeUmProjeto;

/*essa classe irah criar varios casos de teste soh para setar valores para cada uma das
 *variaveis que substituem os system.in da classe .java a ser testada.
 *Para isso, ela precisa dos valores que o usuario forneceu para cada uma dessas variaveis*/
public class PreparaCasosDeTesteSetVariaveisEntrada 
{
	private LinkedList<String> valoresFornecidosPeloUsuarioParaVariaveisSystemIn;
	
	private LinkedList<DeclaracaoDeMetodo> metodosComSetsParaVariaveisSystemIn;
	
	private int quantasVariaveisForamCriadasParaSystemIn;
	
	public PreparaCasosDeTesteSetVariaveisEntrada
				(LinkedList<String> valoresFornecidosPeloUsuarioParaVariaveisSystemIn)
	{
		this.valoresFornecidosPeloUsuarioParaVariaveisSystemIn =
							valoresFornecidosPeloUsuarioParaVariaveisSystemIn;
		this.quantasVariaveisForamCriadasParaSystemIn = 0;
	}
	
	public LinkedList<CasoDeTeste> criarCasosDeTesteSetVariaveisEntrada(String enderecoParaArquivoJavaQueCriamos)
	{
		String caminhoAteNovaPastaComJavaEClassQueCriamos = "backupsTestable";
		
		String nomeClasseAssociadaAoCasoDeTeste =
				obterNomeDaClasseASerTestada(enderecoParaArquivoJavaQueCriamos);
		
		FachadaManipulacaoClassesDeUmProjeto fachadaClassesDeUmProjeto =
									FachadaManipulacaoClassesDeUmProjeto.getInstance();
		AssociaClassesEMetodosANomes conhecedorDasClassesDoProjetoESeusNomes =
									fachadaClassesDeUmProjeto.getAssociaClassesEMetodosANomes();
		System.out.println("PreparaCasosDeTeste trabalha com classe de nome:" + nomeClasseAssociadaAoCasoDeTeste);
		
		@SuppressWarnings("rawtypes")
		Class classeQueVamosTestar = conhecedorDasClassesDoProjetoESeusNomes.pegarClasseDeNome(nomeClasseAssociadaAoCasoDeTeste);
		
		this.pegarTodasAsDeclaracoesDeMetodosSetParaEntradas
							(classeQueVamosTestar, enderecoParaArquivoJavaQueCriamos);
		
		LinkedList<CasoDeTeste> casosDeTesteSetVariaveisEntrada =
				this.criarCasosDeTesteComBaseEmInformacoesRecolhidas
					(caminhoAteNovaPastaComJavaEClassQueCriamos, nomeClasseAssociadaAoCasoDeTeste);
		
		return casosDeTesteSetVariaveisEntrada;
		
	}
	
	private void pegarTodasAsDeclaracoesDeMetodosSetParaEntradas
							(@SuppressWarnings("rawtypes") Class classeQueVamosTestar, String enderecoParaArquivoJavaQueCriamos)
	{
		metodosComSetsParaVariaveisSystemIn = new LinkedList<DeclaracaoDeMetodo>();
		Method[] metodosDaClasse = classeQueVamosTestar.getMethods();
		
		int percorredorMetodosDaClasse = 0;
		while(percorredorMetodosDaClasse < metodosDaClasse.length)
		{
			Method umMetodo = metodosDaClasse[percorredorMetodosDaClasse];
			if(umMetodo.getName().contains("setVariavelTestTableEntrada" + quantasVariaveisForamCriadasParaSystemIn) == true)
			{
				DeclaracaoDeMetodo declaracaoUmMetodo =
						new DeclaracaoDeMetodo(umMetodo, enderecoParaArquivoJavaQueCriamos);
				//o sistema nao consegue identificar nem o cabecalho e nem os parametros de entrada,iremos botar a mao esses dois
				
				declaracaoUmMetodo.setCabecalhoDoMetodo("void setVariavelTestTableEntrada" +
						this.quantasVariaveisForamCriadasParaSystemIn + "(String novoValor)");
				
				LinkedList<String> nomesParametrosDeEntrada = new LinkedList<String>();
				nomesParametrosDeEntrada.add("novoValor");
				declaracaoUmMetodo.setNomesDosParametrosDeEntrada(nomesParametrosDeEntrada);
				this.quantasVariaveisForamCriadasParaSystemIn =
						quantasVariaveisForamCriadasParaSystemIn + 1;
				this.metodosComSetsParaVariaveisSystemIn.add(declaracaoUmMetodo);
				percorredorMetodosDaClasse = 0;
			}
			else
			{
				percorredorMetodosDaClasse = percorredorMetodosDaClasse + 1;
			}
		}
	}
	
	private String obterNomeDaClasseASerTestada(String enderecoParaArquivoJavaModificado)
	{
		String[] stringSplitadaPorBarras = enderecoParaArquivoJavaModificado.split("/");
		String parteDoEnderecoComNomeDaClasseEExtensaoJava =
				stringSplitadaPorBarras[stringSplitadaPorBarras.length - 1];
		String nomeClasseJavaSemExtensao =
				parteDoEnderecoComNomeDaClasseEExtensaoJava.replaceAll(".java", "");
		nomeClasseJavaSemExtensao = nomeClasseJavaSemExtensao.replace(".c", "");
		String nomeClasseASerTestada = nomeClasseJavaSemExtensao.replace(" ", "");
		
		return nomeClasseASerTestada;
	}
	
	
	private LinkedList<CasoDeTeste> criarCasosDeTesteComBaseEmInformacoesRecolhidas
					(String enderecoDoProjetoDaClasseATestar, String nomeClasseAssociadaAoCasoDeTeste)
	{
		LinkedList<CasoDeTeste> casosDeTesteCriados = new LinkedList<CasoDeTeste>();
		
		/*primeiro criaremos os casos de teste para os sets de variaveis que substituem System.in*/
		int quantasVariaveisSystemInForamCriadas =
				valoresFornecidosPeloUsuarioParaVariaveisSystemIn.size();
		for(int i = 0; i < quantasVariaveisSystemInForamCriadas; i++)
		{
			CasoDeTeste casoDeTeste = new CasoDeTeste();
			casoDeTeste.setIdCasoDeTeste(i);
			casoDeTeste.setEnderecoDoProjetoDaClasseATestar(enderecoDoProjetoDaClasseATestar);
			casoDeTeste.setNomeClasseAssociadaAoCasoDeTeste(nomeClasseAssociadaAoCasoDeTeste);
			casoDeTeste.setMetodo(this.metodosComSetsParaVariaveisSystemIn.get(i));
			
			LinkedList<Object> valoresParaOsParametrosDoMetodo = new LinkedList<Object>();
			String valorParaSetDeUmaVariavelSystemIn =
					this.valoresFornecidosPeloUsuarioParaVariaveisSystemIn.get(i);
			valoresParaOsParametrosDoMetodo.add(valorParaSetDeUmaVariavelSystemIn);
			
			casoDeTeste.setValoresDosParametrosDoMetodo(valoresParaOsParametrosDoMetodo);
			casoDeTeste.setValorEsperadoDaSaida(null); //metodos set() nao tem saida
			casoDeTeste.setCasoDeTesteEstahCompleto(true);
			
			casosDeTesteCriados.add(casoDeTeste);
		}
		
		return casosDeTesteCriados;
	}
}
